package datastructures;

import java.util.BitSet;

public class CarrierIndex {	
	//Each bitset is a vector of individuals. e.g. 2000 cases => a bitset of 2000 bits, 
	//with each bit set to 1 if the individual is a carrier, 0 if not.
	private BitSet[] caseStatus;
	private BitSet[] controlStatus;

	public CarrierIndex(int numberOfVariables) { 
		caseStatus = new BitSet[numberOfVariables];
		controlStatus = new BitSet[numberOfVariables];
	}  

	public void setCaseCarrierIndex(BitSet caseCarriers, int variable) {
		caseStatus[variable] = caseCarriers;
	}

	public void setControlCarrierIndex(BitSet controlCarriers, int variable) {
		controlStatus[variable] = controlCarriers;
	}


	public BitSet getCaseCarrierIndex(int variable) {
		return (BitSet) caseStatus[variable].clone();
	}

	public BitSet getControlCarrierIndex(int variable) {
		return (BitSet) controlStatus[variable].clone();
	}


	public int[][] getObservedCaseCarriers(UserParameters userParams, int[] variableArray) {
		assert variableArray.length == 2;

		BitSet var1, var1not, var2, var2not ;
		BitSet temp111, temp110, temp101, temp100;
		int[][] noOfCaseCarriers = new int[2][2];

		var1 = getCaseCarrierIndex( variableArray[0] );
		var1not = (BitSet) var1.clone();
		var1not.flip(0, userParams.getNumber_of_cases());

		var2 = getCaseCarrierIndex( variableArray[1] );
		var2not = (BitSet) var2.clone();
		var2not.flip(0, userParams.getNumber_of_cases());

		temp111 = new BitSet(userParams.getNumber_of_cases());
		temp111.set(0, userParams.getNumber_of_cases());
		temp110 = (BitSet) temp111.clone();
		temp101 = (BitSet) temp111.clone();
		temp100 = (BitSet) temp111.clone();

		temp111.and(var1); temp111.and(var2);
		temp110.and(var1); temp110.and(var2not);
		temp101.and(var1not); temp101.and(var2);
		temp100.and(var1not); temp100.and(var2not);

		noOfCaseCarriers[1][1] = temp111.cardinality();
		noOfCaseCarriers[1][0] = temp110.cardinality();
		noOfCaseCarriers[0][1] = temp101.cardinality();
		noOfCaseCarriers[0][0] = temp100.cardinality();

		return noOfCaseCarriers;
	}


	public int[][] getObservedControlCarriers(UserParameters userParams, int[] variableArray) {

		assert variableArray.length == 2;

		BitSet var1, var1not, var2, var2not;
		BitSet temp111, temp110, temp101, temp100;
		int[][] noOfControlCarriers = new int[2][2];

		var1 = getControlCarrierIndex( variableArray[0] ); 
		var1not = (BitSet) var1.clone();
		var1not.flip(0, userParams.getNumber_of_controls());

		var2 = getControlCarrierIndex( variableArray[1] );
		var2not = (BitSet) var2.clone();
		var2not.flip(0, userParams.getNumber_of_controls());

		temp111 = new BitSet(userParams.getNumber_of_controls());
		temp111.set(0, userParams.getNumber_of_controls());
		temp110 = (BitSet) temp111.clone();
		temp101 = (BitSet) temp111.clone();
		temp100 = (BitSet) temp111.clone();

		temp111.and(var1); temp111.and(var2);
		temp110.and(var1); temp110.and(var2not);
		temp101.and(var1not); temp101.and(var2);
		temp100.and(var1not); temp100.and(var2not);

		noOfControlCarriers[1][1] = temp111.cardinality();
		noOfControlCarriers[1][0] = temp110.cardinality();
		noOfControlCarriers[0][1] = temp101.cardinality();
		noOfControlCarriers[0][0] = temp100.cardinality();

		return noOfControlCarriers;
	}

}



//public double[][][] getExpectedCaseCarriers(UserParameters userParams, int[] variableArray) {
//BitSet var1, var1not, var2, var2not, var3, var3not;
//double[][][] expectedCaseCarriers = new double[2][2][2];
//
//switch( variableArray.length ) {
//
//	case 1:
//		var1 = getCaseCarrierIndex( variableArray[0] );	
//		var1not = (BitSet) var1.clone();
//		var1not.flip(0, userParams.getNumber_of_cases());
//		expectedCaseCarriers[1][1][1] = var1.cardinality();
//		expectedCaseCarriers[1][1][0] = var1not.cardinality();
//		break;
//
//	case 2:
//		var1 = getCaseCarrierIndex( variableArray[0] );
//		var1not = (BitSet) var1.clone();
//		var1not.flip(0, userParams.getNumber_of_cases());
//		
//		var2 = getCaseCarrierIndex( variableArray[1] );
//		var2not = (BitSet) var2.clone();
//		var2not.flip(0, userParams.getNumber_of_cases());
//		
//		expectedCaseCarriers[1][1][1] = (double) var1.cardinality() * (double) var2.cardinality() / userParams.getNumber_of_cases() ;
//		expectedCaseCarriers[1][1][0] = (double) var1.cardinality() * (double) var2not.cardinality() / userParams.getNumber_of_cases();
//		expectedCaseCarriers[1][0][1] = (double) var1not.cardinality() * (double) var2.cardinality() / userParams.getNumber_of_cases();
//		expectedCaseCarriers[1][0][0] = userParams.getNumber_of_cases() - expectedCaseCarriers[1][0][1] - expectedCaseCarriers[1][1][0] - expectedCaseCarriers[1][1][1];
//		break;
//
//	default: //case 3
//		var1 = getCaseCarrierIndex( variableArray[0] );
//		var1not = (BitSet) var1.clone();
//		var1not.flip(0, userParams.getNumber_of_cases());
//	
//		var2 = getCaseCarrierIndex( variableArray[1] );
//		var2not = (BitSet) var2.clone();
//		var2not.flip(0, userParams.getNumber_of_cases());
//	
//		var3 = getCaseCarrierIndex( variableArray[2] );
//		var3not = (BitSet) var2.clone();
//		var3not.flip(0, userParams.getNumber_of_cases());			
//	
//		expectedCaseCarriers[1][1][1] = (double) var1.cardinality() * (double) var2.cardinality() * (double) var3.cardinality() / Math.pow(userParams.getNumber_of_cases(),2) ;
//		expectedCaseCarriers[1][1][0] = (double) var1.cardinality() * (double) var2.cardinality() * (double) var3not.cardinality() / Math.pow(userParams.getNumber_of_cases(),2) ;
//		expectedCaseCarriers[1][0][1] = (double) var1.cardinality() * (double) var2not.cardinality() * (double) var3.cardinality() / Math.pow(userParams.getNumber_of_cases(),2) ;
//		expectedCaseCarriers[1][0][0] = (double) var1.cardinality() * (double) var2not.cardinality() * (double) var3not.cardinality() / Math.pow(userParams.getNumber_of_cases(),2) ;
//		expectedCaseCarriers[0][1][1] = (double) var1not.cardinality() * (double) var2.cardinality() * (double) var3.cardinality() / Math.pow(userParams.getNumber_of_cases(),2) ;
//		expectedCaseCarriers[0][1][0] = (double) var1not.cardinality() * (double) var2.cardinality() * (double) var3not.cardinality() / Math.pow(userParams.getNumber_of_cases(),2) ;
//		expectedCaseCarriers[0][0][1] = (double) var1not.cardinality() * (double) var2not.cardinality() * (double) var3.cardinality() / Math.pow(userParams.getNumber_of_cases(),2) ;
//		expectedCaseCarriers[0][0][0] = userParams.getNumber_of_cases() - expectedCaseCarriers[0][0][1] - expectedCaseCarriers[0][1][0] - expectedCaseCarriers[0][1][1] - expectedCaseCarriers[1][0][0] - expectedCaseCarriers[1][0][1] - expectedCaseCarriers[1][1][0] - expectedCaseCarriers[1][1][1];
//		break;
//}
//
//return expectedCaseCarriers;
//}



//public double[][][] getExpectedControlCarriers(UserParameters userParams, int[] variableArray) {
//BitSet var1, var1not, var2, var2not, var3, var3not;
//double[][][] expectedControlCarriers = new double[2][2][2];
//
//switch( variableArray.length ) {
//
//	case 1:
//		var1 = getControlCarrierIndex( variableArray[0] );	
//		var1not = (BitSet) var1.clone();
//		var1not.flip(0, userParams.getNumber_of_controls());
//		expectedControlCarriers[1][1][1] = var1.cardinality();
//		expectedControlCarriers[1][1][0] = var1not.cardinality();
//		break;
//
//	case 2:
//		var1 = getControlCarrierIndex( variableArray[0] );
//		var1not = (BitSet) var1.clone();
//		var1not.flip(0, userParams.getNumber_of_controls());
//		
//		var2 = getControlCarrierIndex( variableArray[1] );
//		var2not = (BitSet) var2.clone();
//		var2not.flip(0, userParams.getNumber_of_controls());
//		
//		expectedControlCarriers[1][1][1] = (double) var1.cardinality() * (double) var2.cardinality() / userParams.getNumber_of_controls() ;
//		expectedControlCarriers[1][1][0] = (double) var1.cardinality() * (double) var2not.cardinality() / userParams.getNumber_of_controls() ;
//		expectedControlCarriers[1][0][1] = (double) var1not.cardinality() * (double) var2.cardinality() / userParams.getNumber_of_controls() ;
//		expectedControlCarriers[1][0][0] =  userParams.getNumber_of_controls() - expectedControlCarriers[1][0][1] - expectedControlCarriers[1][1][0] - expectedControlCarriers[1][1][1];
//		break;
//
//	default: //case 3
//		var1 = getControlCarrierIndex( variableArray[0] );
//		var1not = (BitSet) var1.clone();
//		var1not.flip(0, userParams.getNumber_of_controls());
//	
//		var2 = getControlCarrierIndex( variableArray[1] );
//		var2not = (BitSet) var2.clone();
//		var2not.flip(0, userParams.getNumber_of_controls());
//	
//		var3 = getControlCarrierIndex( variableArray[2] );
//		var3not = (BitSet) var2.clone();
//		var3not.flip(0, userParams.getNumber_of_controls());			
//	
//		expectedControlCarriers[1][1][1] = (double) var1.cardinality() * (double) var2.cardinality() * (double) var3.cardinality() / Math.pow(userParams.getNumber_of_controls(),2) ;
//		expectedControlCarriers[1][1][0] = (double) var1.cardinality() * (double) var2.cardinality() * (double) var3not.cardinality() / Math.pow(userParams.getNumber_of_controls(),2) ;
//		expectedControlCarriers[1][0][1] = (double) var1.cardinality() * (double) var2not.cardinality() * (double) var3.cardinality() / Math.pow(userParams.getNumber_of_controls(),2) ;
//		expectedControlCarriers[1][0][0] = (double) var1.cardinality() * (double) var2not.cardinality() * (double) var3not.cardinality() / Math.pow(userParams.getNumber_of_controls(),2) ;
//		expectedControlCarriers[0][1][1] = (double) var1not.cardinality() * (double) var2.cardinality() * (double) var3.cardinality() / Math.pow(userParams.getNumber_of_controls(),2) ;
//		expectedControlCarriers[0][1][0] = (double) var1not.cardinality() * (double) var2.cardinality() * (double) var3not.cardinality() / Math.pow(userParams.getNumber_of_controls(),2) ;
//		expectedControlCarriers[0][0][1] = (double) var1not.cardinality() * (double) var2not.cardinality() * (double) var3.cardinality() / Math.pow(userParams.getNumber_of_controls(),2) ;
//		expectedControlCarriers[0][0][0] = userParams.getNumber_of_controls() - expectedControlCarriers[0][0][1] - expectedControlCarriers[0][1][0] - expectedControlCarriers[0][1][1] - expectedControlCarriers[1][0][0] - expectedControlCarriers[1][0][1] - expectedControlCarriers[1][1][0] - expectedControlCarriers[1][1][1];
//		break;
//}
//
//return expectedControlCarriers;
//}
